home *** CD-ROM | disk | FTP | other *** search
- Path: keats.ugrad.cs.ubc.ca!not-for-mail
- From: c2a192@ugrad.cs.ubc.ca (Kazimir Kylheku)
- Newsgroups: comp.lang.c,comp.lang.c++
- Subject: Re: sizeof() question >>> :)
- Date: 14 Apr 1996 09:00:12 -0700
- Organization: Computer Science, University of B.C., Vancouver, B.C., Canada
- Message-ID: <4kr7ecINN16d@keats.ugrad.cs.ubc.ca>
- References: <1996Apr12.061927@topaz>
- NNTP-Posting-Host: keats.ugrad.cs.ubc.ca
-
- In article <1996Apr12.061927@topaz>, <naderr@topaz.cqu.edu.au> wrote:
- >Hi,
- >
- >How can I get, with a pointer, the sizeof of an array that is
- >pointed by the pointer ? (No it's not a tounge twister :)
- >
- >Ok, let see if with an example I could clarify what I'm trying to say,
- >
- >
- > char First_name[20];
- > char Last_name[20];
- > char Address[60];
- > char Phone[20];
- > char **ct, *cp;
- > char *record[4];
- > char ch;
- >
- > record[0] = First_name;
- > record[1] = Last_name;
- > record[2] = Address;
- > record[3] = Phone;
- > ct = record;
- > cp = *ct;
- >
- > while (!done) {
- > ch = getchar();
- > if (cp - *ct < sizeof(XXXXXXX)-1) {
- > *cp++ = ch;
- > } else {
- > beep();
- > }
- > }
- >
- >for XXXXXXX the _only_ thing that I can find that works is to stick
- >in there is the actual array that cp is pointing to, i.e. sizeof(First_name).
- >
- >What ideas do you have so that I can get the size of the array currently
- >pointed to by cp?
-
- You mean the remaining bytes in the object into which cp points? This is not
- possible. The type that cp points to is a single char, so sizeof *cp is the same
- thing as sizeof (char). sizeof First_Name works to give you the entire size
- because First_Name is an lvalue expression that names an array object.
-
- Ignore the replies that mention strlen(), since this function is inapplicable
- to your problem at all. They are completely off mark (that's what you get for
- cross-posting what is essentially a C question to comp.lang.c++).
-
- The string length (as defined by C Language and the strlen() standard defined
- function) of your arrays is either: 1) *zero* if they are *static*, since they
- will be initialized to contain all zero chars, or 2) *undefined* if they are
- automatic, since the contents are undefined, and may not necessarily include a
- zero character. The strlen() function cannot be used to determine the size of
- these character arrays.
-
- Your real problem is that cp could point to the first element of any one of a
- number of different character arrays. The record[] array holds only the pointer
- to the first character of these arrays, not any size information.
-
- May I suggest an alternative representation to the one you are using? You
- should really be using the C ``struct'' facility to represent records, not
- fields.
-
- Place these declarations into a ``person.h'' header file. This can be included
- by any module which wants to access the person record.
-
-
- typedef char firstnm_t[20];
- typedef char lastnm_t[20];
- typedef char address_t[60];
- typedef char phoneno_t[20];
-
- typedef struct person {
- firstnm_t First_Name;
- lastnm_t Last_Name;
- address_t Address;
- phoneno_t Phone;
- } person;
-
-
- int read_person(struct person *P, FILE *f);
-
- The reason I would use typedef names for the various fields is simple. Suppose
- that these persons are users, and later on I want to declare a structure which
- associates some data to users. I may want to use their phone number, say, as an
- identifier. Without the typedef name ``phoneno_t'', I will have to declare this
- separately as a 20-char array. Then later if I want to change the length of a
- phone number, I will have to hunt for all the places that use phone numbers
- instead of changing just one type.
-
- phoneno_t A, B;
-
- ...
-
- memcpy(B, A, sizeof(phoneno_t));
-
- Some C programmers would rather not make a typedef name for the structure, and
- always refer to it with a qualified type expression ``struct person''.
- The identifier following the ``struct'' keyword is a ``tag name'': union and
- struct tag names have their own space separate from other identifiers, so it's
- OK to have a ``person'' type name as well as a ``struct person'' structure.
-
- In the implementation portion, ``person.c'', you define the function
- read_person(), as well as a function for reading character fields called
- ``readfield''. The fgets() function could also be used to implement readfield()
- with slightly different semantics. With fgets(), you could not quite as readily
- discriminate between input that just perfectly fits the field array size and
- one which is de facto too long, since fgets() does not look forward to the
- lookahead once it has read enough characters to satisfy the buffer size less
- one character.
-
- #include <stdio.h>
- #include "person.h"
-
- int readfield(char *b, size_t s, FILE *f)
-
- {
- char c;
-
- /* while there are two or more characters of space in buffer
- b, and there is no EOF or end of line on reading f... */
-
- while(s > 1 && ((c = getc(f)) != EOF) && c != '\n') {
- *b++ = c; /* add the character */
- s--; /* decrement avail. char count */
- }
-
- if (s > 0) { /* if there is space */
- *b++ = '\0'; /* null terminate */
- s--;
- }
-
- /* if EITHER the buffer is precisely filled and we have
- not just seen a newline character (field is too long)
- OR an EOF condition has been detected on the stream,
- return failure */
-
- if (!s && c != '\n' || c == EOF)
- return 0;
-
- return 1; /* otherwise success */
- }
-
- /***
- *
- * The above function could be written, perhaps more succintly, as
- *
- * #include <string.h>
- *
- * int readfield(char *b, size_t s, FILE *f)
- *
- * {
- * char *nl;
- *
- * if (!fgets(b, s, f))
- * return 0;
- *
- * The check here is that if no newline is found in the string obtained
- * from fgets() (and there is at most one, thus strchr rather than
- * strrchr is used) then the field is too long, UNLESS the next input
- * character in f is a newline, which we readily gobble.
- *
- * if (!(nl = strchr(b, '\n')))
- * if (getc(f) != '\n')
- * return 0;
- * else
- * *nl = '\0';
- *
- * And of course, we must overwrite the newline with a zero, if and only
- * if it WAS read in by fgets().
- *
- * return 1;
- * }
- *
- ***/
-
- int read_person(person *P, FILE *f)
-
- {
- if(!readfield(P->First_Name, sizeof(firstnm_t), f))
- return 0;
- if(!readfield(P->Last_Name, sizeof(lastnm_t), f))
- return 0;
- if(!readfield(P->Address, sizeof(address_t), f))
- return 0;
- if(!readfield(P->Phone, sizeof(phoneno_t), f))
- return 0;
- return 1;
- }
-
- The read_person() function calls for a pointer to a person type and a stdio
- file pointer. It returns zero/false if it fails for some reason, at which
- point it would be advisable to check ferror(f) and feof(f). If neither of these
- are true, the reason for failure was that one of the input lines exceed the
- maximum length, causing truncation. If you don't care about this, you might
- want to change readfield() to just truncate without warning.
-
- Caveats: Despite my usually better judgement, I have not tested the code before
- posting. So expect anything. The readfield() function clearly does not belong
- with the ``person.c'' code. It should be by itself, or in a library module
- filled with related functions.
-
- That's my detailed post of this week.
-
- Cheers... Kaz
-